#include "cube.h"
Cube::Cube(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id, f32 len)
: scene::ISceneNode(parent, mgr, id), mesh(0), length(len)
{
	SMeshBuffer* aFace[6];
	for (int i = 0; i < 6; i++)
	{
		aFace[i] = new SMeshBuffer();
	}
	vector3df point1 = vector3df(-0.5 * len, -0.5 * len, -0.5 * len);
	vector3df point2 = vector3df(0.5 * len, -0.5 * len, -0.5 * len);
	vector3df point3 = vector3df(0.5 * len, -0.5 * len, 0.5 * len);
	vector3df point4 = vector3df(-0.5 * len, -0.5 * len, 0.5 * len);
	vector3df point5 = vector3df(-0.5 * len, 0.5 * len, -0.5 * len);
	vector3df point6 = vector3df(0.5 * len, 0.5 * len, -0.5 * len);
	vector3df point7 = vector3df(0.5 * len, 0.5 * len, 0.5 * len);
	vector3df point8 = vector3df(-0.5 * len, 0.5 * len, 0.5 * len);

	vector3df toFront = vector3df(0,0,-1);
	vector3df toLeft = vector3df(-1,0,0);
	vector3df toTop = vector3df(0,1,0);
	const video::SColor clr(255, 255,255,255);
	// front
	aFace[0]->Vertices.push_back(S3DVertex(point1, toFront, clr , vector2df(0, 1)));
	aFace[0]->Vertices.push_back(S3DVertex(point2, toFront, clr , vector2df(1, 1)));
	aFace[0]->Vertices.push_back(S3DVertex(point6, toFront, clr , vector2df(1, 0)));
	aFace[0]->Vertices.push_back(S3DVertex(point5, toFront, clr , vector2df(0, 0)));
	// back
	aFace[1]->Vertices.push_back(S3DVertex(point3, -toFront, clr , vector2df(0, 1)));
	aFace[1]->Vertices.push_back(S3DVertex(point4, -toFront, clr , vector2df(1, 1)));
	aFace[1]->Vertices.push_back(S3DVertex(point8, -toFront, clr , vector2df(1, 0)));
	aFace[1]->Vertices.push_back(S3DVertex(point7, -toFront, clr , vector2df(0, 0)));
	// left
	aFace[2]->Vertices.push_back(S3DVertex(point4, toLeft, clr , vector2df(0, 1)));
	aFace[2]->Vertices.push_back(S3DVertex(point1, toLeft, clr , vector2df(1, 1)));
	aFace[2]->Vertices.push_back(S3DVertex(point5, toLeft, clr , vector2df(1, 0)));
	aFace[2]->Vertices.push_back(S3DVertex(point8, toLeft, clr , vector2df(0, 0)));
	// rigth
	aFace[3]->Vertices.push_back(S3DVertex(point2, -toLeft, clr , vector2df(0, 1)));
	aFace[3]->Vertices.push_back(S3DVertex(point3, -toLeft, clr , vector2df(1, 1)));
	aFace[3]->Vertices.push_back(S3DVertex(point7, -toLeft, clr , vector2df(1, 0)));
	aFace[3]->Vertices.push_back(S3DVertex(point6, -toLeft, clr , vector2df(0, 0)));
	// top
	aFace[4]->Vertices.push_back(S3DVertex(point5, toTop, clr , vector2df(0, 1)));
	aFace[4]->Vertices.push_back(S3DVertex(point6, toTop, clr , vector2df(1, 1)));
	aFace[4]->Vertices.push_back(S3DVertex(point7, toTop, clr , vector2df(1, 0)));
	aFace[4]->Vertices.push_back(S3DVertex(point8, toTop, clr , vector2df(0, 0)));
	// bottom
	aFace[5]->Vertices.push_back(S3DVertex(point4, -toTop, clr , vector2df(0, 1)));
	aFace[5]->Vertices.push_back(S3DVertex(point3, -toTop, clr , vector2df(1, 1)));
	aFace[5]->Vertices.push_back(S3DVertex(point2, -toTop, clr , vector2df(1, 0)));
	aFace[5]->Vertices.push_back(S3DVertex(point1, -toTop, clr , vector2df(0, 0)));
	// 3-------2
	// |       |
	// |       |
	// 0-------1
	core::array<u16> indices;
	indices.push_back(3);
	indices.push_back(1);
	indices.push_back(0);
	indices.push_back(3);
	indices.push_back(2);
	indices.push_back(1);
	video::IVideoDriver* driver = SceneManager->getVideoDriver();
	aFace[0]->Material.setTexture(0, id & IDFlag_FRONT ? driver->getTexture("front.png") : driver->getTexture("inside.png"));
	aFace[1]->Material.setTexture(0, id & IDFlag_BACK ? driver->getTexture("back.png") : driver->getTexture("inside.png"));
	aFace[2]->Material.setTexture(0, id & IDFlag_LEFT ? driver->getTexture("left.png") : driver->getTexture("inside.png"));
	aFace[3]->Material.setTexture(0, id & IDFlag_RIGHT ? driver->getTexture("right.png") : driver->getTexture("inside.png"));
	aFace[4]->Material.setTexture(0, id & IDFlag_TOP ? driver->getTexture("top.png") : driver->getTexture("inside.png"));
	aFace[5]->Material.setTexture(0, id & IDFlag_BOTTOM ? driver->getTexture("bottom.png") : driver->getTexture("inside.png"));

	video::ITexture* NormalMap = driver->getTexture("inside.bmp");
	if (NormalMap)
		driver->makeNormalMapTexture(NormalMap, 2.0f);
	SMesh* Smesh = new SMesh();
	for (int i = 0; i < 6; i++)
	{
		// load heightmap, create normal map from it and set it
		if (NormalMap)
		{
			aFace[i]->Material.setTexture(1, NormalMap);
			aFace[i]->Material.MaterialType = video::EMT_PARALLAX_MAP_SOLID;
		}
		aFace[i]->Indices = indices;
		aFace[i]->Material.Wireframe = false;
		aFace[i]->Material.Lighting = true;
		aFace[i]->Material.AntiAliasing = EAAM_LINE_SMOOTH;
		aFace[i]->BoundingBox.reset(aFace[i]->Vertices[0].Pos);
		for (int j = 1; j < 4; j++)
		{
			aFace[i]->BoundingBox.addInternalPoint(aFace[i]->Vertices[j].Pos);
		}
		Smesh->addMeshBuffer(aFace[i]);
		aFace[i]->drop();
	}
	Smesh->setHardwareMappingHint(EHM_STATIC);
	Smesh->recalculateBoundingBox();
	mesh = Smesh;
}
Cube::~Cube(void)
{
	if (mesh)
		mesh->drop();
}
void Cube::OnRegisterSceneNode()
{
	if (IsVisible)
		SceneManager->registerNodeForRendering(this);
	ISceneNode::OnRegisterSceneNode();
}
const core::aabbox3d<f32>& Cube::getBoundingBox() const
{
	return mesh->getBoundingBox();
}
u32 Cube::getMaterialCount() const
{
	return mesh->getMeshBufferCount();
}
video::SMaterial& Cube::getMaterial(u32 i)
{
	return mesh->getMeshBuffer(i)->getMaterial();
}
void Cube::render()
{
	video::IVideoDriver* driver = SceneManager->getVideoDriver();
	if (mesh && driver)
	{
		u32 bufCount = mesh->getMeshBufferCount();
		for (u32 i = 0; i < bufCount; i++)
		{
			driver->setMaterial(mesh->getMeshBuffer(i)->getMaterial());
			driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
			driver->drawMeshBuffer(mesh->getMeshBuffer(i));
		}
	}
}

void Cube::OnAnimate(u32 timeMs)
{
	if (IsVisible)
	{
		ISceneNodeAnimatorList::Iterator ait = Animators.begin();
		while (ait != Animators.end())
		{
			ISceneNodeAnimator* anim = *ait;
			if (anim->hasFinished())
			{
				anim->drop();
				Animators.erase(ait);
			}
			else
			{
				++ait;
				anim->animateNode(this, timeMs);
			}
		}

		updateAbsolutePosition();

		ISceneNodeList::Iterator it = Children.begin();
		for (; it != Children.end(); ++it)
			(*it)->OnAnimate(timeMs);
	}
}

bool Cube::hasStop()
{
	ISceneNodeAnimatorList::Iterator ait = Animators.begin();
	while (ait != Animators.end())
	{
		ISceneNodeAnimator* anim = *ait++;
		if (!anim->hasFinished())
			return false;
	}
	return true;
}

void Cube::setParent(ISceneNode* newParent)
{
	grab();
	remove();

	Parent = newParent;

	if (Parent)
		Parent->addChild(this);
	int id = getID();
	RelativeTranslation = AbsoluteTransformation.getTranslation();
	core::vector3df rot =  AbsoluteTransformation.getRotationDegrees();
	RelativeRotation = rot;
	drop();
}
